﻿using System;
using System.Linq.Expressions;
using CSW.Framework.Common;

namespace CSW.Framework.Linq
{
    /// <summary>
    /// Where
    /// </summary>
    public class Where<TSource> : IWhere
    {
        private readonly string m_FieldName;
        private readonly ComparisonType m_ComparisonType;
        private readonly object m_Value;
        private readonly Type m_ValueType;

        /// <summary>
        /// Adds the specified caption.
        /// </summary>
        /// <param name="field">The field.</param>
        /// <param name="comparison">The comparison.</param>
        /// <param name="value">The value.</param>
        /// <param name="valueType">Type of the value.</param>
        internal Where(LambdaExpression field, ComparisonType comparison, object value, Type valueType)
        {
            Guard.ArgumentNotNull(field, "field");
            Guard.ArgumentNotNull(valueType, "valueType");

            m_FieldName = LinqToSqlHelper.GetFieldName(field);
            m_ComparisonType = comparison;
            m_ValueType = valueType;

            if (m_ValueType == typeof(string) && string.IsNullOrEmpty((string)value))
                m_Value = null;
            else
                m_Value = value;
        }

        /// <summary>
        /// Adds the specified caption.
        /// </summary>
        /// <param name="field">The field.</param>
        /// <param name="comparison">The comparison.</param>
        /// <param name="value">The value.</param>
        /// <param name="valueType">Type of the value.</param>
        internal Where(LambdaExpression field, string comparison, object value, Type valueType)
        {
            Guard.ArgumentNotNull(field, "field");
            Guard.ArgumentNotNullOrEmptyString(comparison, "comparison");
            Guard.ArgumentNotNull(valueType, "valueType");

            m_FieldName = LinqToSqlHelper.GetFieldName(field);
            m_ValueType = valueType;
            if (m_ValueType == typeof(string) && string.IsNullOrEmpty((string)value))
                m_Value = null;
            else
                m_Value = value;

            switch (comparison)
            {
                case "=":
                case "==":
                    m_ComparisonType = ComparisonType.Equals;
                    break;

                default:
                    throw new NotSupportedException(string.Format("Comparison '{0}' not supported.", comparison));
            }
        }

        /// <summary>
        /// Creates a Where&lt;T&gt;.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="field">The field.</param>
        /// <param name="comparison">The comparison.</param>
        /// <param name="value">The value.</param>
        public static Where<TSource> Create<TResult>(Expression<Func<TSource, TResult>> field, ComparisonType comparison, object value)
        {
            return new Where<TSource>(field, comparison, value, typeof(TResult));
        }

        /// <summary>
        /// Creates a Where&lt;T&gt;.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <param name="field">The field.</param>
        /// <param name="comparison">The comparison.</param>
        /// <param name="value">The value.</param>
        public static Where<TSource> Create<TResult>(Expression<Func<TSource, TResult>> field, string comparison, object value)
        {
            return new Where<TSource>(field, comparison, value, typeof(TResult));
        }

        /// <summary>
        /// Gets the name of the field.
        /// </summary>
        /// <value>The name of the field.</value>
        public string FieldName
        {
            get { return m_FieldName; }
        }

        /// <summary>
        /// Gets the type of the comparison.
        /// </summary>
        /// <value>The type of the comparison.</value>
        public ComparisonType ComparisonType
        {
            get { return m_ComparisonType; }
        }

        /// <summary>
        /// Gets the value.
        /// </summary>
        /// <value>The value.</value>
        public object Value
        {
            get { return m_Value; }
        }

        /// <summary>
        /// Gets the type of the value.
        /// </summary>
        /// <value>The type of the value.</value>
        public Type ValueType
        {
            get { return m_ValueType; }
        }
    }
}